package cn.kevinkun.Tween;

import java.util.ArrayList;
import java.util.List;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.DesignerProperty;
import com.google.appinventor.components.annotations.Options;
import com.google.appinventor.components.annotations.PropertyCategory;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.AndroidViewComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;
import com.google.appinventor.components.runtime.util.YailList;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;
import cn.kevinkun.Tween.helpers.Property;

@DesignerComponent(version = 4, //
		description = "Tween Extension to make animtion by changing the property of component", //
		category = ComponentCategory.EXTENSION, //
		nonVisible = true, //
		iconName = "aiwebres/icon.png", //
		helpUrl = "https://kevinkun.cn/tween")
@SimpleObject(external = true)
public class Tween extends AndroidNonvisibleComponent {

	int repeatCount = 0;
	int repeatMode = 1;
//	int cycles = 1;
	int interpolator = 5;
	long duration = 500;
	long startDelay = 0;
	boolean isTogether = true;
	Activity activity;
	List<ObjectAnimator> animatorList = new ArrayList<ObjectAnimator>();
	AnimatorSet animatorSet = new AnimatorSet();

	public Tween(ComponentContainer container) {
		super(container.$form());
		activity = container.$context();
	}

	@SimpleFunction(description = "add an animation to a set. \n\n"//
			+ "property:including but not limited to X, Y, TranslationX, TranslationY, ScaleX, ScaleY, RotationX, RotationY, RotationZ, BackgroundColor, TextColor\n\n"//
			+ "values: list of property values. ")
	public void AddToSet(AndroidViewComponent component, @Options(Property.class) String property, YailList values) {
		View view = component.getView();
		ObjectAnimator animator;
		if (property.toLowerCase().contains("color")) {
			int[] array = new int[values.size()];
			for (int i = 1; i <= values.size(); i++) {
				array[i - 1] = Integer.parseInt(values.get(i).toString());
			}
			animator = ObjectAnimator.ofInt(view, property, array);
			animator.setEvaluator(new ArgbEvaluator());
		} else {
			float[] array = new float[values.size()];
			for (int i = 1; i <= values.size(); i++) {
				array[i - 1] = Float.parseFloat(values.get(i).toString());
			}
			animator = ObjectAnimator.ofFloat(view, property, array);
		}

		animator.setRepeatCount(repeatCount);
		animator.setRepeatMode(repeatMode);
		setInterpolator(animator, interpolator);
		animator.setStartDelay(startDelay);
		animator.setDuration(duration);

		animatorList.add(animator);

	}

	@SimpleFunction(description = "start the animation set")
	public void StartSet() {

		Animator[] array = new Animator[animatorList.size()];
		for (int i = 0; i < animatorList.size(); i++) {
			array[i] = animatorList.get(i);
		}
		animatorSet = new AnimatorSet();
		if (isTogether) {
			animatorSet.playTogether(array);
		} else {
			animatorSet.playSequentially(array);
		}
		animatorSet.addListener(new AnimatorListener() {

			@Override
			public void onAnimationStart(Animator arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onAnimationRepeat(Animator arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onAnimationEnd(Animator arg0) {
				// TODO Auto-generated method stub
				OnAnimationEnd();
			}

			@Override
			public void onAnimationCancel(Animator arg0) {
				// TODO Auto-generated method stub

			}
		});

		animatorSet.start();
		animatorList = new ArrayList<ObjectAnimator>();

	}

	@SimpleFunction
	public void PauseSet() {
		animatorSet.pause();
	}

	@SimpleFunction
	public void CancelSet() {
		animatorSet.cancel();

	}

	@SimpleFunction
	public void ResumeSet() {
		animatorSet.resume();
	}

	@SimpleFunction
	public void ReverseSet() {
		animatorSet.reverse();
	}

	private void setInterpolator(ObjectAnimator animator, int index) {
		switch (index) {
		case 1:
			animator.setInterpolator(new AccelerateDecelerateInterpolator());
			break;
		case 2:
			animator.setInterpolator(new AccelerateInterpolator());
			break;
		case 3:
			animator.setInterpolator(new DecelerateInterpolator());
			break;
		case 4:
			animator.setInterpolator(new BounceInterpolator());
			break;
		case 5:
			animator.setInterpolator(new LinearInterpolator());
			break;
		case 6:
			animator.setInterpolator(new AnticipateOvershootInterpolator());
			break;
		case 7:
			animator.setInterpolator(new AnticipateInterpolator());
			break;
		case 8:
			animator.setInterpolator(new OvershootInterpolator());
			break;
		default:
			animator.setInterpolator(new AccelerateDecelerateInterpolator());
			break;
		}
	}

	@SimpleEvent
	public void OnAnimationEnd() {
		EventDispatcher.dispatchEvent(this, "AnimationEnd");
	}

	@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_NON_NEGATIVE_INTEGER, defaultValue = "5")
	@SimpleProperty(description = "int number. type of interpolator, from 1 to 8", category = PropertyCategory.BEHAVIOR)
	public void Interpolator(int index) {
		if (index < 1 || index > 9) {
			index = 1;
		}
		this.interpolator = index;
	}

	@SimpleProperty
	public int Interpolator() {
		return interpolator;
	}

	@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "True")
	@SimpleProperty(description = "true for play together, false for play sequentially", category = PropertyCategory.BEHAVIOR)
	public void IsTogether(boolean isTogether) {
		this.isTogether = isTogether;
	}

	@SimpleProperty(description = "true for play together, false for play sequentially")
	public boolean IsTogether() {
		return this.isTogether;
	}

	@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_INTEGER, defaultValue = "0")
	@SimpleProperty(description = "-1 for infinity", category = PropertyCategory.BEHAVIOR)
	public void RepeatCount(int count) {
		this.repeatCount = count;
	}

	@SimpleProperty(description = "-1 for infinity")
	public int RepeatCount() {
		return this.repeatCount;
	}

	@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_INTEGER, defaultValue = "500")
	@SimpleProperty(description = "in millis, for single animation only", category = PropertyCategory.BEHAVIOR)
	public void Duration(long duration) {
		this.duration = duration;
	}

	@SimpleProperty(description = "")
	public long Duration() {
		return this.duration;
	}

	@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_INTEGER, defaultValue = "0")
	@SimpleProperty(description = "for single animation only", category = PropertyCategory.BEHAVIOR)
	public void StartDelay(long startDelay) {
		this.startDelay = startDelay;
	}

	@SimpleProperty(description = "for single animation only")
	public long StartDelay() {
		return this.startDelay;
	}

	@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_INTEGER, defaultValue = "1")
	@SimpleProperty(description = "1 for restart, 2 for reverse", category = PropertyCategory.BEHAVIOR)
	public void RepeatMode(int mode) {
		if (!(mode == 1 || mode == 2)) {
			mode = 1;
		}
		this.repeatMode = mode;
	}

	@SimpleProperty(description = "1 for restart, 2 for reverse")
	public int RepeatMode() {
		return this.repeatMode;
	}

	@SimpleFunction
	public float ScreenDensity() {
		return form.deviceDensity();
	}

}
